#ifndef __NETWORK_H__
#define __NETWORK_H__

#include <vector>
#include "actor.h"
#include "newtypes.h"

#include <iostream>                  // for std::cout
#include <utility>                   // for std::pair
#include <algorithm>                 // for std::for_each
using namespace std;

#include <boost/graph/adjacency_list.hpp>
#include <boost/unordered_map.hpp>
using namespace boost;

//typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
typedef adjacency_list < listS, vecS,
undirectedS, no_property, property < edge_weight_t, double > > Graph;

typedef boost::unordered_map<int, vector<int>*> unorderedMap;

//typedef adjacency_list < setS, setS,
//		undirectedS, no_property, property < edge_weight_t, double, property<edge_weight2_t, double> > >  Graph2;


class Actor;
// TODO: Name it Network or Graph?
// TODO: src, dest - are they zero-based or 1-based?
class Network
{
	// Data
public:
	// Data structure. Pls. modify appropriately. Pls. make sure that memory
	// is allocated and de-allocated appropriately.
	// int** adjMatrix;
private:
	Graph *g;
	// - not needed now as Srinath and Subbu decided
	//vector<Actor*> actorList;
	unorderedMap* distanceMap;
	bool* staleInformation;

	// Methods
public:
	Network();

	Network(int numOfVertices, double density);

	// copy constructor.
	Network( const Network& ntwk );

	~Network();

	// Initialializes the network object - not needed now
	//   (1) setup the initial edges (randomly) from density parameter
	//   (2) Create the actors and store a ptr to each actor in vecActors
	// void init();


	// Return the number of edges on the geodesic (shortest path) between
	// srcNode and destNode
	int getNumEdgesOnGeodesic( int srcNode, int destNode ) const;

	// classify and return the network structure
	// uses: (1) sorted in-out degree vector
	//       (2) total mean squared deviation (structural fit metric)
	NTWK_STRUCT getNetworkStructure(ofstream *ofile, int &k_partite);


	// adds an edge between 'src' and 'dest' nodes
	void add( int src, int dest );

	// deletes/removes the edge between 'src' and 'dest' nodes
	// NOTE: 'delete' is a keyword in C++. So, could not use that for method name.
	void remove( int src, int dest );


	// TODO: Discuss whether the adjecency matrix should be accessible outside this class
	// Good programming means that we should not have access to this matrix.

	// If the network data structure is exposed to outside world, then the following method may not be required.
	// Returns true if 'dest' is adjacent to 'dest'. Returns false otherwise.
	bool isAdjacent( int src, int dest ) const;


	// Dumps the current state of the network to the specified file.
	// Uses append mode.
	// TODO: Header to identify the start of a new dump (Rohith and Greg to decide)
	void dumpNetwork( const char* fileName );

	// returns the sum of all utilities of actors in the network - not needed now as Srinath and Subbu decided
	// double getUtility();

	// returns the actors in the network - not needed now as Srinath and Subbu decided
	//const vector<Actor*>& getActors() const;

	// returns a ref to boost graph object
	const Graph& getGraph() const;

	const bool* getStaleInformationList()const;
	const unorderedMap* getUnorderedMap()const;

	double getSparsity(int src) const;

	// is dest reachable by at max 2-hops from the src?
	// bool isTwoHopNeighbor( int src, int dest ) const;

	// return the number of neighbors of src
	int getNumNeighbors( int src ) const;

	// is this graph a complete multi-partite network?
	bool isCompleteMultipartiteNetwork();

	static void visualizeGraph(int noOfVertices, const std::vector<Edge>& edgeList, char *fileName)
	{
		Network* trialNetwork = new Network(noOfVertices, 0);
		for (unsigned i=0;i<edgeList.size();i++){
			trialNetwork->add(edgeList[i].srcVertex, edgeList[i].destVertex);
		}
		trialNetwork->dumpNetwork(fileName);
	}

	int getNumOfDirectLinksAmongNeighbours(int) const;
private:
	Network operator = (const Network &);

protected:
};


#endif
